# -*- coding: utf-8 -*-
import os
import sys
import time
from StringIO import StringIO
from .gzip import GzipMiddleware
from ..globals import request
############################################################################
__all__ = ['ProfilerMiddleware', 'TimeMiddleware', 'ChangeProcessTitleMiddleware',
'ExceptionTemplateMiddleware', 'GzipMiddleware', 'StormSQLMiddleware']


try:
    try:
        from cProfile import Profile
    except ImportError:
        from profile import Profile
    from pstats import Stats
    available = True
except ImportError:
    available = False


class ProfilerMiddleware(object):
    """Simple profiler middleware.  Wraps a WSGI application and profiles
    a request.  This intentionally buffers the response so that timings are
    more exact.

    For the exact meaning of `sort_by` and `restrictions` consult the
    :mod:`profile` documentation.

    :param app: the WSGI application to profile.
    :param stream: the stream for the profiled stats.  defaults to stderr.
    :param sort_by: a tuple of columns to sort the result by.
    :param restrictions: a tuple of profiling strictions.
    """

    def __init__(self, app, stream=None,
                 sort_by=('time', 'calls'), restrictions=()):
        if not available:
            raise RuntimeError('the profiler is not available because '
                               'profile or pstat is not installed.')
        self._app = app
        self._stream = stream or sys.stdout
        self._sort_by = sort_by
        self._restrictions = restrictions

    def __call__(self, environ, start_response):
        if not environ.get("HTTP_PROFILE"):
            return self._app(environ, start_response)
        response_body = []

        def catching_start_response(status, headers, exc_info=None):
            start_response(status, headers, exc_info)
            return response_body.append

        def runapp():
            appiter = self._app(environ, catching_start_response)
            response_body.extend(appiter)
            if hasattr(appiter, 'close'):
                appiter.close()

        p = Profile()
        p.runcall(runapp)
        body = ''.join(response_body)
        stats = Stats(p, stream=self._stream)
        stats.sort_stats(*self._sort_by)

        self._stream.write('-' * 80)
        self._stream.write('\nPATH: %r\n' % environ.get('PATH_INFO'))
        stats.print_stats(*self._restrictions)
        self._stream.write('-' * 80 + '\n\n')
        if hasattr(self._stream, "flush"):
            self._stream.flush()

        return [body]


class StormSQLMiddleware(object):
    def __init__(self, application):
        self.application = application

    def __call__(self, environ, start_response):
        try:
            from storm import tracer
        except:
            return self.application(environ, start_response)
        sql_log = StringIO()
        tracer.remove_all_tracers()
        tracer.install_tracer(tracer.DebugTracer(sql_log))
        def new_start_response(status, headers, exc_info=None):
            l = filter(bool, sql_log.getvalue().split("\n"))
            l = filter(lambda log: not log.endswith("DONE"), l)
            for i, log in enumerate(l):
                headers.append(('X-sql-%d'%(i+1,), log))
            return start_response(status, headers, exc_info)
        return self.application(environ, new_start_response)


class TimeMiddleware(object):
    def __init__(self, application):
        self.application = application

    def __call__(self, environ, start_response):
        request_time = time.time()
        def new_start_response(status, headers, exc_info=None):
            t = int((time.time() - request_time) * 1000)
            headers.append(('X-Runtime', str(t)))
            headers.append(('X-PID', str(os.getpid())))
            return start_response(status, headers, exc_info)
        return self.application(environ, new_start_response)


class ExceptionTemplateMiddleware(object):
    """need jinja2"""
    def __init__(self, application, status, env, tmpl_name):
        self.application = application
        self.status = status
        self.env = env
        self.tmpl_name = tmpl_name

    def __call__(self, environ, start_response):
        def new_start_response(status, headers, exc_info=None):
            self.real_status = status
            return start_response(status, headers, exc_info)
        result = self.application(environ, new_start_response)
        if self.status == self.real_status:
            return [self.env.get_template(self.tmpl_name).render(request=request).encode('utf-8')]
        else:
            return result


if os.name == 'posix':
    try:
        import ctypes
    except ImportError:
        libc = None
    else:
        try:
            libc = ctypes.CDLL('/lib/libc.so.6')  
        except:
            libc = None
else:
    libc = None
class ChangeProcessTitleMiddleware(object):
    def __init__(self, application):
        self.application = application

    def __call__(self, environ, start_response):
        if environ['wsgi.multiprocess'] and os.name == 'posix':
            procname = environ['PATH_INFO']
            libc.prctl(15, '%s\0'%procname, 0, 0, 0)
        return self.application(environ, start_response)
